#ifndef CXX_STUDY_SHARED_POINTER_HPP
#define CXX_STUDY_SHARED_POINTER_HPP

#include <cstdlib>

namespace cxx_study {

  /**
   * 共享指针
   * */
  template<typename _Tp>
  class shared_ptr {
    typedef void (*_Deleter)(_Tp *);

  public:
    shared_ptr() : count_(nullptr), ptr_(nullptr) {}

    shared_ptr(_Tp *ptr, _Deleter deleter = nullptr) : deleter_(deleter) {
      if (ptr == nullptr) ptr_ = nullptr;
      else {
        ptr_ = ptr;
        count_ = new std::size_t(1);
      }
    }

    shared_ptr(const shared_ptr &rhs) {
      count_ = rhs.count_;
      ptr_ = rhs.ptr_;
      deleter_ = rhs.deleter_;

      (*count_)++;
    }

    shared_ptr(shared_ptr &&rhs) noexcept {
      count_ = rhs.count_;
      ptr_ = rhs.ptr_;
      deleter_ = rhs.deleter_;

      rhs.count_ = nullptr;
      rhs.ptr_ = nullptr;
      rhs.deleter_ = nullptr;
    }

    shared_ptr &operator=(const shared_ptr &rhs) {
      if (this == &rhs)return *this;

      shared_ptr tmp(rhs);
      swap(tmp);

      return *this;
    }

    shared_ptr &operator=(_Tp *rhs) {
      if (rhs == ptr_)return *this;

      shared_ptr tmp(rhs);
      swap(tmp);
      return *this;
    }

    ~shared_ptr() {
      if (count_ && --*count_ <= 0) {
        if (deleter_)deleter_(ptr_);
        else delete (ptr_);
        delete (count_);
      }
    }

    void swap(shared_ptr &rhs) {
      std::swap(count_, rhs.count_);
      std::swap(ptr_, rhs.ptr_);
      std::swap(deleter_, rhs.deleter_);
    }

    _Tp *get() {
      return ptr_;
    }

    inline std::size_t use_count() const {
      return count_ ? *count_ : 0;
    }

  private:
    std::size_t *count_;
    _Tp *ptr_;
    _Deleter deleter_;
  };


  template<typename _Tp, typename... _Args>
  shared_ptr<_Tp> make_share_ptr(_Args... args) {
    return shared_ptr<_Tp>(new _Tp(std::forward<_Args>(args)...));
  }
}

#endif //CXX_STUDY_SHARED_POINTER_HPP
